home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
cgazv5n4.arc
/
SCRLTEXT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-23
|
11KB
|
385 lines
/***************************************************************
* File: SCRLTEXT.C
* Purpose: Simple demo of 2-D scrolling
* Date: February 1991
* Author: George Spofford
* Compilers: MSC 6.0, Turbo C++ 1.0, MetaWare HighC-386 1.7
* Switches:
* MSC 6.0: -- large model
* cl -AL -c scrltest.c
* link scrltest+vidprim;
* High C: -- needs both hce.lib and na.lib
* hc386 -c -DDOS_386 scrltest.c
* 386link scrltest vidprim -lib hce.lib na.lib
*
* Object code may be used freely. Source code may be used freely
* if author and publication are acknowledged.
****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include "vidprim.h"
#define U_ARROW 72
#define D_ARROW 80
#define L_ARROW 75
#define R_ARROW 77
#define PGUP 73
#define PGDN 81
#define HOME 71
#define END 79
#define TRUE 1
#define FALSE 0
#define TCALLOC( t, n) (t *) calloc (n, sizeof (t))
#define TMALLOC( t, n) (t *) malloc (n * sizeof (t))
#define MAXLINE 512
typedef struct slist_st {
char *str;
struct slist_st *next, *prev;
} slist_t;
typedef struct { /* text-scroll object's
state template */
bbox_t bbox; /* bounding box */
slist_t *first, *last; /* first and last lines on screen */
slist_t *LHead, *LTail; /* first and last lines of text */
int acrossO; /* character pos of left edge */
} TextListState_t;
typedef enum {
Repaint, UpLine, DownLine, LeftChar, RightChar,
PageUp, PageDown, Home, End
} ScrollMsg_e;
/* This construct will be used frequently
when drawing text lines */
#define PLACESL(r, o, p) \
if (strlen (p->str) > o->acrossO) /* if long enough to show */ \
x_outtext (r, 0, p->str + o->acrossO) /* show what's visible */
int ReadLines (FILE *fp, int tabsize);
TextListState_t *InitTextScroller (bbox_t *bbp,
slist_t *ListHead,
slist_t *ListTail);
void ScrollTextObj (TextListState_t *tsp,
ScrollMsg_e Msg);
void ScrollLines (void);
void TabExpand (char *out, char *in,
int tabsize);
slist_t *ListHead, *ListTail; /* text-lines to be viewed */
void main (int argc, char *argv[])
{
FILE *fp;
int tabsize = 5; /* size of tabs in spaces */
if (argc < 2) {
fputs ("args: text-file-path [tabsize]\n", stderr);
exit (1);
}
if (NULL == (fp = fopen (argv[1], "r"))) {
fprintf (stderr, "cannot open '%s'\n", argv[1]);
exit (2);
}
if (argc == 3)
tabsize = atoi (argv[2]);
if ( ! ReadLines (fp, tabsize)) {
fprintf (stderr,
"error occurred reading '%s'\n", argv[1]);
exit (3);
}
fclose (fp);
/* set up display */
InitDisplay (3, 25);
CursorOff ();
ScrollLines ();
SetCurAttrib (MK_ATTR( CGA_BLACK, CGA_WHITE));
ClearScreen ();
SetTextCursor (0, 0);
}
/* ScrollLines: Display what text fits in box,
** respond to keystrokes to scroll text around.
*/
void ScrollLines (void)
{
bbox_t bbox;
TextListState_t *tsp; /* scroller object ptr */
int c;
BBSET( bbox, 5, 10, 15, 60); /* set box for scroller */
if (NULL == (tsp =
InitTextScroller (&bbox, ListHead, ListTail)))
return;
SetCurAttrib (MK_ATTR( CGA_BLACK, CGA_GREEN));
/* assume that current box is whole screen
when function is invoked */
x_outtext (0, 0,
"Press Q to quit, arrow keys to scroll around");
bbox.o[DOWN] -= 1; bbox.o[ACROSS] -= 1; /* expand box */
bbox.n[DOWN] += 2; bbox.n[ACROSS] += 2;
/* make a visible pane */
SetCurAttrib (MK_ATTR( CGA_MAGENTA, CGA_MAGENTA));
ClearBox (&bbox);
SetCurAttrib (MK_ATTR( CGA_BLACK, CGA_CYAN));
ScrollTextObj (tsp, Repaint);
for (;;) {
c = getch ();
if (c == 'Q' || c == 'q') /* check for quit key */
break;
if (c != 0) /* if not extended key, wait for next one */
continue;
switch (getch ()) { /* process extended key */
case U_ARROW: ScrollTextObj (tsp, UpLine); break;
case D_ARROW: ScrollTextObj (tsp, DownLine); break;
case R_ARROW: ScrollTextObj (tsp, RightChar); break;
case L_ARROW: ScrollTextObj (tsp, LeftChar); break;
case PGUP: ScrollTextObj (tsp, PageUp); break;
case PGDN: ScrollTextObj (tsp, PageDown); break;
case HOME: ScrollTextObj (tsp, Home); break;
case END: ScrollTextObj (tsp, End); break;
default:
break;
}
}
}
/* InitTextScroller
** Allocates and initializes a text-scroll state object.
*/
TextListState_t *InitTextScroller (bbox_t *bbp,
slist_t *ListHead, slist_t *ListTail)
{
TextListState_t *new;
if (NULL != (new = TMALLOC( TextListState_t, 1))) {
memcpy (&new->bbox, bbp, sizeof (bbox_t));
/* set first on screen to head */
new->LHead = new->first = ListHead;
new->LTail = ListTail;
new->acrossO = 0; /* at leftmost char pos */
}
return (new);
}
/* ScrollTextObj
** Simple message handler for text-scroll object.
*/
void ScrollTextObj (TextListState_t *self, ScrollMsg_e Msg)
{
slist_t *p;
int i, j;
SetCurBox (&self->bbox); /* make window current */
switch (Msg) {
case Repaint:
ClearBox (&self->bbox); /* clear it out */
/* show first of lines */
for (i = 0, p = self->first; i < self->bbox.n[DOWN] && p;
++i, p = p->next) {
PLACESL( i, self, p); /* place on screen */
self->last = p; /* track last line */
}
break;
case UpLine:
if (self->first->prev == NULL)
break;
ScrollBox (&self->bbox, 1, 0); /* scroll down one */
self->first = self->first->prev; /* previous lines */
self->last = self->last->prev;
PLACESL( 0, self, self->first); /* put top line on screen */
break;
case DownLine:
if (self->last->next == NULL)
break;
ScrollBox (&self->bbox, -1, 0); /* scroll up one */
self->last = self->last->next; /* next lines */
self->first = self->first->next;
/* put bottom line on screen */
PLACESL( self->bbox.n[DOWN] - 1, self, self->last);
break;
case RightChar:
++self->acrossO; /* advance right */
ScrollBox (&self->bbox, 0, -1); /* scroll left */
/* for each line on screen, place newly visible
character if line is long enough to have one */
for (i = 0, p = self->first; p && i < self->bbox.n[DOWN];
++i, p = p->next)
if (strlen (p->str) >=
self->acrossO + self->bbox.n[ACROSS])
x_outch (i, self->bbox.n[ACROSS]-1,
p->str[ self->acrossO + self->bbox.n[ACROSS] - 1]);
break;
case LeftChar:
if (self->acrossO == 0)
break;
--self->acrossO; /* left one character */
ScrollBox (&self->bbox, 0, 1); /* scroll screen right */
/* for each line on screen, place newly visible
character if line is long enough to have one */
for (i = 0, p = self->first; p && i < self->bbox.n[DOWN];
++i, p = p->next)
if (strlen (p->str) > self->acrossO)
x_outch (i, 0, p->str[self->acrossO]);
break;
case PageUp:
if (self->first->prev == NULL)
break;
/* work upwards by one screenful or until top,
count the number of lines involved */
for (i = 0; self->first->prev != NULL &&
i < self->bbox.n[DOWN]; ++i) {
self->first = self->first->prev;
self->last = self->last->prev;
}
/* scroll down by # of new lines */
ScrollBox (&self->bbox, i, 0);
/* put top lines on screen */
for (j = 0, p = self->first; j < i; ++j, p = p->next)
PLACESL( j, self, p);
break;
case PageDown:
if (self->last->next == NULL)
break;
/* work downwards by one screenful or until bottom,
count the number of lines involved */
for (i = 0; self->last->next != NULL &&
i < self->bbox.n[DOWN]; ++i) {
self->first = self->first->next;
self->last = self->last->next;
}
/* scroll up by # of new lines */
ScrollBox (&self->bbox, -i, 0);
/* put bottom lines on screen if long enough to show */
/* j in 1..i equivalent to j in 0..i-1 used with
bbp->n[DOWN] - 1 - j */
for (j = 1, p = self->last; j <= i; p = p->prev, ++j)
PLACESL( self->bbox.n[DOWN] - j, self, p);
break;
case Home:
if (self->first->prev == NULL && self->acrossO == 0)
break;
self->acrossO = 0;
self->first = self->LHead;
ScrollTextObj (self, Repaint); /* simply repaint */
break;
case End:
if (self->last->next == NULL && self->acrossO == 0)
break;
self->acrossO = 0;
self->last = self->LTail;
/* from tail, count up one screenful or
until head reached */
for (i = 0, p = self->last; p->prev != NULL &&
i < self->bbox.n[DOWN]; ++i) {
self->first = p;
p = p->prev;
}
ScrollTextObj (self, Repaint); /* simply repaint */
break;
default:
break;
}
}
/* ReadLines: Reads text lines into a doubly-linked list.
** Returns false on (memory) error.
*/
int ReadLines (FILE *fp, int tabsize)
{
slist_t *new;
char buf[MAXLINE];
char expand[MAXLINE];
char *p;
while (fgets (buf, MAXLINE, fp)) {
if (NULL != (p = strchr (buf, '\n')))
*p = '\0';
TabExpand (expand, buf, tabsize);
/* for some reason, MetaWare's strdup() doesn't behave here
* on zero-length strings, so just explicitly calloc()
* and strcpy () */
if ( NULL == (new = TCALLOC( slist_t, 1)) ||
NULL == (new->str = TMALLOC (char, 1 + strlen (expand))) )
return (FALSE);
strcpy (new->str, expand);
if (ListHead == NULL)
ListHead = ListTail = new;
else {
ListTail->next = new;
new->prev = ListTail;
ListTail = new;
}
}
return (TRUE);
}
/* TabExpand - expand tabs to spaces for display */
void TabExpand (char *to, char *from, int ntabsp)
{
char *t;
char *f;
int nsp; /* # of spaces to add upon '\t' */
for (t = to, f = from; *f; ++f)
if (*f == '\t') {
/* nsp = # of sp. 'til next tab-stop */
nsp = ntabsp - ((t-to) % ntabsp);
memset (t, ' ', nsp);
t += nsp;
}
else
*t++ = *f;
*t = '\0';
}
/* END OF SCRLTEXT.C */